package com.ydl.learning.scala

/**
  * 隐式参数
  * https://docs.scala-lang.org/zh-cn/tour/implicit-parameters.html
  *
  * @author ydl
  * @since 2021/3/18
  */
object ImplicitParameters {

  /**
    * 类 Monoid 定义了一个名为 add 的操作，它将一对 A 类型的值相加并返回一个 A，以及一个名为 unit 的操作，用来创建一个（特定的）A 类型的值。
    * @tparam A
    */
  abstract class Monoid[A] {
    def add(x: A, y: A): A

    def unit: A
  }

  implicit val stringMonoid: Monoid[String] = new Monoid[String] {
    def add(x: String, y: String): String = x concat y

    def unit: String = ""
  }

  implicit val intMonoid: Monoid[Int] = new Monoid[Int] {
    def add(x: Int, y: Int): Int = x + y

    def unit: Int = 0
  }

  /**
    * 方法可以具有 隐式 参数列表，由参数列表开头的 implicit 关键字标记。
    * 如果参数列表中的参数没有像往常一样传递， Scala 将查看它是否可以获得正确类型的隐式值，如果可以，则自动传递。
    * m被标记为隐式参数
    *
    * @param xs
    * @param m
    * @tparam A
    * @return
    */
  def sum[A](xs: List[A])(implicit m: Monoid[A]): A =
    if (xs.isEmpty) m.unit
    else m.add(xs.head, sum(xs.tail))

  def main(args: Array[String]): Unit = {
    println(sum(List(1, 2, 3))) // uses IntMonoid implicitly
    println(sum(List("a", "b", "c"))) // uses StringMonoid implicitly
  }

}
